#include "app_message.h"
#include "cJSON/cJSON.h"
#include "log/log.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 十六进制字符映射表
static const char hexChars[] = "0123456789abcdef";

// 函数定义：将十六进制字符串转换为二进制值
unsigned char *hexToBin(const char *hexStr, int *binLength) {
    int length = strlen(hexStr);
    if (length % 2 != 0) {
        fprintf(stderr, "Error: Hexadecimal string length must be even.\n");
        return NULL;
    }

    // 计算输出二进制数组的长度
    *binLength = length / 2;

    // 分配内存存放二进制数据
    unsigned char *binData = (unsigned char *)malloc(*binLength);
    if (binData == NULL) {
        fprintf(stderr, "Error: Memory allocation failed.\n");
        return NULL;
    }

    // 转换十六进制字符串为二进制数据
    for (size_t i = 0; i < length; i += 2) {
        char highNibble = hexStr[i];
        char lowNibble = hexStr[i + 1];

        // 检查字符是否为有效的十六进制字符
        if (!isxdigit(highNibble) || !isxdigit(lowNibble)) {
            free(binData);
            fprintf(stderr, "Error: Invalid hexadecimal character found.\n");
            return NULL;
        }

        // 将十六进制字符转换为数值
        int highVal = (strchr(hexChars, tolower(highNibble)) - hexChars) << 4;
        int lowVal = (strchr(hexChars, tolower(lowNibble)) - hexChars);

        // 将两个半字节合并成一个字节
        binData[i / 2] = (unsigned char)(highVal + lowVal);
    }

    return binData;
}

// 函数定义：将二进制数据转换为十六进制字符串
unsigned char *binToHex(const unsigned char *binData, size_t binLength) {
    // 计算十六进制字符串的长度
    size_t hexLength = binLength * 2 + 1; // +1 用于存储 null 终止符
    unsigned char *hexStr = (char *)malloc(hexLength);
    if (hexStr == NULL) {
        fprintf(stderr, "Error: Memory allocation failed.\n");
        return NULL;
    }

    // 转换二进制数据为十六进制字符串
    for (size_t i = 0; i < binLength; i++) {
        unsigned char byte = binData[i];
        hexStr[i * 2] = hexChars[(byte >> 4) & 0x0F]; // 高四位
        hexStr[i * 2 + 1] = hexChars[byte & 0x0F];     // 低四位
    }
    hexStr[hexLength - 1] = '\0'; // 添加 null 终止符

    return hexStr;
}

Message *app_message_initByBinary(char *ptr, int len)
{
    Message *msg = (Message *)malloc(sizeof(Message));
    if (msg == NULL) {
        log_warn("malloc Message failed");
        return NULL;
    }

    memcpy(&msg->conn_type, ptr, 1);
    memcpy(&msg->id_len, ptr + 1, 1);
    memcpy(&msg->msg_len, ptr + 2, 1);

    if (len != 3 + msg->id_len + msg->msg_len) {
        log_warn("binary message length error");
        free(msg);
        return NULL;
    }

    msg->payload = malloc(msg->id_len + msg->msg_len);
    if (msg->payload == NULL) {
        log_warn("malloc payload failed");
        free(msg);
        return NULL;
    }
    memcpy(msg->payload, ptr + 3, msg->id_len + msg->msg_len);
    
    log_debug("initByBinary sucess, conn_type:%d, id_len:%d, msg_len:%d, payload:%s", 
        msg->conn_type, msg->id_len, msg->msg_len, msg->payload);
    return msg;
}

Message *app_message_initByJson(char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (root == NULL) {
        log_warn("parse json failed");
        return NULL;
    }

    Message *msg = (Message *)malloc(sizeof(Message));
    if (msg == NULL) {
        log_warn("malloc Message failed");
        cJSON_Delete(root);
        return NULL;
    }

    msg->conn_type = cJSON_GetObjectItem(root, "conn_type")->valueint;
    char *idHexStr = cJSON_GetObjectItem(root, "id")->valuestring;
    char *idBinary = hexToBin(idHexStr, &msg->id_len);
    
    char *msgHexStr = cJSON_GetObjectItem(root, "msg")->valuestring;
    char *msgBinary = hexToBin(msgHexStr, &msg->msg_len);

    msg->payload = malloc(msg->id_len + msg->msg_len);
    memcpy(msg->payload, idBinary, msg->id_len);
    memcpy(msg->payload + msg->id_len, msgBinary, msg->msg_len);

    log_debug("initByJson sucess, conn_type:%d, id_len:%d, msg_len:%d, payload:%s", 
        msg->conn_type, msg->id_len, msg->msg_len, msg->payload);

    free(idBinary);
    free(msgBinary);
    cJSON_Delete(root);

    return msg;
}

int app_message_toBinary(Message *msg, char *ptr, int len)
{
    if (len < 3 + msg->id_len + msg->msg_len) {
        log_warn("binary buffer length error");
        return -1;
    }

    memcpy(ptr, &msg->conn_type, 1);
    memcpy(ptr + 1, &msg->id_len, 1);
    memcpy(ptr + 2, &msg->msg_len, 1);
    memcpy(ptr + 3, msg->payload, msg->id_len + msg->msg_len);
    log_debug("toBinary sucess, conn_type:%d, id_len:%d, msg_len:%d, payload:%s", msg->conn_type, msg->id_len, msg->msg_len, msg->payload);
    return 3 + msg->id_len + msg->msg_len;
}

int app_message_toJson(Message *msg, char *json, int len)
{
    cJSON *root = cJSON_CreateObject();
    if (root == NULL) {
        log_warn("create json object failed");
        return -1;
    }

    cJSON_AddNumberToObject(root, "conn_type", msg->conn_type);

    char *idHexStr = binToHex(msg->payload, msg->id_len);
    char *msgHexStr = binToHex(msg->payload + msg->id_len, msg->msg_len);

    cJSON_AddStringToObject(root, "id", idHexStr);
    cJSON_AddStringToObject(root, "msg", msgHexStr);

    char *jsonStr = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    if (jsonStr == NULL) {
        log_warn("print json failed");
        return -1;
    }
    if (strlen(jsonStr) +1 > len) {
        log_warn("json buffer length error");
        free(jsonStr);
        return -1;
    }

    strcpy(json, jsonStr);
    free(jsonStr);

    return 0;
}

void app_message_free(Message *message)
{
    if (message->payload) {
        free(message->payload);
    }
    free(message);
}